﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace SupplyChain
{

    #region Business Layer

    #region Application Logic

    public class SupplyChainContext
    {
        static SupplyChainContext()
        {
            ProjectEndDate = new DateTime(2009, 01, 01);
            ProjectStartDate = new DateTime(2008, 01, 01);
            EstimatedParticipants = 4000;
            ProductTypes = new List<ProductType>()
            {
                new ProductType()
                {
                    Name = "Apples"
                },
                new ProductType()
                {
                    Name = "Bananas"
                }
            };
        }

        public static DateTime ProjectStartDate { get; set; }
        public static DateTime ProjectEndDate { get; set; }
        public static DateTime FirstParticipant { get; private set; }
        public static DateTime LastParticipant { get; private set; }
        public static int EstimatedParticipants { get; set; }
        public static List<ProductType> ProductTypes { get; set; }
    }

    #endregion

    #region Domain Logic

    public class BusinessObjectBase
    {
        public virtual long Id { get; private set; }
        private DateTime _CreatedDate = DateTime.Now;
        public virtual DateTime CreatedDate
        {
            get
            {
                return _CreatedDate;
            }
            set
            {
                _CreatedDate = value;
            }
        }
        private DateTime _ModifiedDate = DateTime.Now;
        public virtual DateTime ModifiedDate
        {
            get
            {
                return _ModifiedDate;
            }
            set
            {
                _ModifiedDate = value;
            }
        }

    }

    public class SupplyChainEntity : BusinessObjectBase
    {
        public SupplyChainEntity()
        {
            this.Inventory = new Inventory();
            this.Campaigns = new List<Campaign>();
            this.Orders = new List<Order>();
        }

        public virtual string Name { get; set; }
        public virtual Inventory Inventory { get; set; }
        public virtual IList<Campaign> Campaigns { get; set; }
        public virtual IList<Order> Orders { get; set; }
        public delegate void PlaceOrderHandler(object sender);
        public virtual event PlaceOrderHandler PlaceOrderEvent;

        /// <summary>
        /// Places an order for specific products from 
        /// a specific supplier. Only products in stock 
        /// at the supplier can be included in an order.
        /// </summary>
        public virtual Order PlaceOrder(Order order)
        {
            if (this.PlaceOrderEvent != null)
            {
                PlaceOrderEvent(this);
            }
            order.Validate();
            return order;
        }

        /// <summary>
        /// Confirms the receipt of a shipment from a supplier.
        /// The inventory is adjusted with the confirmed contents
        /// of the shipment. Any issues associated with the shipment
        /// are logged and the supplier will be notified.
        /// </summary>
        public virtual void ReceiveShipment()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Gets all orders that do not have associated shipment(s) that
        /// have been confirmed as received and whose contents fulfill 
        /// the associated order.
        /// </summary>
        public virtual void GetOutstandingOrders()
        {
            throw new NotImplementedException();
        }

        /// <summary>
        /// Allows inventory managers to adjust the stock levels in 
        /// the system to reflect the physical inventory. Inventory 
        /// stock levels can be increased or decreased, and a reason
        /// must be specified.
        /// </summary>
        public virtual void AdjustInventory()
        {
            throw new NotImplementedException();
        }
    }

    public class Inventory : BusinessObjectBase
    {
        public Inventory()
        {
            this.InventoryItems = new List<InventoryItem>();
        }

        public virtual SupplyChainEntity SupplyChainEntity { get; set; }
        public virtual IList<InventoryItem> InventoryItems { get; set; }

        public virtual int Total(ProductType productType)
        {
            return this.InventoryItems.SingleOrDefault(c => c.Batch.ProductType == productType).Quantity;
        }
    }

    public class InventoryItem : BusinessObjectBase
    {
        public virtual Batch Batch { get; set; }
        public virtual DateTime ExpiryDate { get; set; }
        public virtual int Quantity { get; set; }
        public virtual Inventory Inventory { get; set; }
    }

    public class Order : BusinessObjectBase, IValidatable
    {
        public Order()
        {
            this.OrderLineItems = new List<OrderLineItem>();
        }

        private List<ValidationResult> _ValidationResults;
        public virtual List<ValidationResult> ValidationResults 
        {
            get
            {
                return _ValidationResults;
            }
        }
        public virtual string OrderKey { get; set; }
        public virtual DateTime OrderDate { get; set; }
        public virtual SupplyChainEntity Supplier { get; set; }
        public virtual SupplyChainEntity Consumer { get; set; }
        public virtual IList<OrderLineItem> OrderLineItems { get; set; }
        public virtual int OrderLineItemCount 
        {
            get
            {
                return this.OrderLineItems.Count();
            }
        }

        /// <summary>
        /// Validates an order based on the validation rules specified
        /// in this method.
        /// </summary>
        /// <param name="order"></param>
        /// <returns></returns>
        public virtual List<ValidationResult> Validate()
        {
            _ValidationResults = new List<ValidationResult>();
            return ValidationResults;
        }

    }

    public class OrderLineItem : BusinessObjectBase
    {
        public virtual Batch Batch { get; set; }
        public virtual int Quantity { get; set; }
        public virtual IList<ShipmentLineItem> ShipmentLineItems { get; set; }
    }

    public class Shipment : BusinessObjectBase
    {
        public Shipment()
        {
            this.ShipmentLineItems = new List<ShipmentLineItem>();
        }
        public virtual string ShipmentKey { get; set; }
        public virtual DateTime ShipmentDate { get; set; }
        public virtual IList<ShipmentLineItem> ShipmentLineItems { get; set; }
    }

    public class ShipmentLineItem : BusinessObjectBase
    {
        public virtual OrderLineItem OrderLineItem { get; set; }
        public virtual int Quantity { get; set; }
    }

    public class Batch : BusinessObjectBase
    {
        public virtual string BatchKey { get; set; }
        public virtual ProductType ProductType { get; set; }
        public virtual int Quantity { get; set; }
        public virtual IList<InventoryItem> InventoryItems { get; set; }
    }

    public class Campaign : BusinessObjectBase
    {
        public virtual IList<Batch> Batches { get; set; }
    }

    public class ProductType
    {
        public string Name { get; set; }
    }

    public class ValidationResult
    {
    }

    #endregion

    #region Interfaces

    public interface IValidatable
    {
        List<ValidationResult> ValidationResults { get; }
        List<ValidationResult> Validate();
    }

    #endregion

    #endregion

}
